<?php
namespace app\common\pay\alipay;
use think\Db;
class Pc{
  public $config = [];
  public $puclicdata = [];
  public $filtParam = [];

  //初始化配置参数
  public function __construct($uuid){
      $rs = Db::name("pay_method")->where("uuid",$uuid)->value("config");
      $rs = json_decode(htmlspecialchars_decode($rs),true);
      $temp = [
          'partner'				=>	'2088721142454730',
          'sign_type'			=>	'RSA',
          '_input_charset'=>	strtolower('UTF-8'),
          'seller_email'	=>	'wuguodong@hstwkj.com',
          'alipay_public_key'		=>	'alipay_public_key.pem',
          'private_key'	        =>	'tw_private_key.pem',
          'public_key'          =>  '',
          'pay_url'				      =>	'https://mapi.alipay.com/gateway.do?',
          'notify_url'          =>  '',
          'return_url'          =>  '',
          'md5key'              =>  'anrr44y1h8w6n76qmhi9umyrid8htx0y',
          'it_b_pay'            =>  '15m',
      ];
      //t(json_encode($temp));
      $this->config=array_merge($temp, $rs);
      //加密时需要过滤的参数
      $this->filtParam=["sign","sign_type"];
      //加载配置
      $this->config($this->config);
  }


  /**
   * 成功返回
   */
  public function success()
  {
      return "success";
  }

  /**
   * 成功返回
   */
  public function error()
  {
      return "error";
  }

  /**
   * 设置生成加密串需要忽略的参数
   * @param array $Param
   */
  public function filt_Param($Param=[]){
      if(gettype($Param)=="array" && count($Param)>0)
      {
          $this->filtParam=array_merge($this->filtParam,$Param);
      }
  }


  /**
   * 设置配置
   * @param array $config
   *  $config['partner'] 开发者编号
   *  string $config['alipay_public_key'] 支付宝公钥文件
   *  string $config['private_key'] 证书私钥
   *  string $config['seller_id'] 卖家账号
   *  string $config['notify_url'] 页面通知地址[禁止带get参数]
   *  string $config['sign_type'] 加密类型:md5|rsa MD5加密必需传md5key,rsa必需传alipay_public_key与private_key
   */
  public function config($config=array())
  {
      if(gettype($config) && count($config)>0){
          foreach($config as $key=>$val)
          {
              if(array_key_exists($key,$this->config) && gettype($val)=="string" && $val!=''){
                  $this->config[$key]=(string)$val;
              }
          }
      }
      $this->puclicdata=array();
      $this->publicdata();
  }


  /**
   * 发起支付
   * @param number $money 支付的金额以元为单位，精确到分
   * @param string $subject 产品名称
   * @param string $orderno 订单号
   * @param string $comments 备注
   */
  public function pay($money=0,$orderno='',$subject='消费',$comments="消费")
  {
      $data= array(
          'service'				=>	'create_direct_pay_by_user',
          'out_trade_no'			=>	$orderno,
          'subject'				=>	$subject,
          'payment_type'			=>	'1',
          'seller_email'		    =>	$this->config['seller_email'],
          'total_fee'				=>	$money,
          'body'					=>	$comments,
          '_input_charset'        =>   $this->config['_input_charset'],
      );
      $data= array_merge($data,$this->publicdata);

      $data['sign']				=	$this->sign($data);

      $this->_log($data,'pay');

      return [
          'type'=>'content',
          'data'=>$this->buildRequestForm($data,'post','正在发起支付宝支付，请稍候..'),
      ];
  }

  /**notice**
   *开始通知
   */
  public function notice()
  {
      $this->_log($_REQUEST,"notice");

      $data=array(
          "code"=>1, #0|成功，1|有错误
          'msg'=>'success', #返回给第三方的信息
          'data'=>array(
              'out_trade_no'=>'', #要处理的订单号
              'total_fee'=>0, #用户支付的金额
              'buy_info'=>'', #付款用户的呢称
              'pay_data'=>'',#第三方订单号
          ),
      );


      if(count($_REQUEST)==0){
          $data['msg']="参数不完整";
          return $data;
      }

      //通知校验
      if($this->notice_check($_REQUEST,$this->g("sign")))
      {
          if($this->g('trade_status')!='' && $this->g('out_trade_no')!='' && $this->g('total_fee')!='')
          {
              //开始业务处理
              if($this->g('trade_status')=='TRADE_SUCCESS')
              {
                  $data['code']=0;
                  $data['data']['out_trade_no']=$this->g("out_trade_no");
                  $data['data']['total_fee']=$this->g("total_fee");
                  $data['data']['buy_info']=$this->g("buyer_email");
                  $data['data']['pay_data']=json_encode($_REQUEST,JSON_UNESCAPED_UNICODE);
              }
          }
          else
          {
              $data['msg']= 'trade_status,out_trade_no,total_fee其中一项为空';
          }
      }
      else
      {
          $data['msg']="签名错误";
      }
      return $data;
  }

  /**
   * 返回发起支付表单
   * @param array $para
   * @param string $method
   * @param string $button_name
   * @return string
   */
  private function buildRequestForm($para=[], $method="post", $button_name="正在发起支付,请稍等...") {
      //待请求参数数组

      $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='{$this->config["pay_url"]}_input_charset={$this->config['_input_charset']}'  method='".$method."'>\r\n";

      unset($para['_input_charset']);
      while (list ($key, $val) = each ($para)) {
          $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>\r\n";
      }

      //submit按钮控件请不要含有name属性
      $sHtml = $sHtml."<input type='submit' value='".$button_name."'></form>";

      $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";

      return $sHtml;
  }

  /**
   * 加载支付插件配置
   */
  private function publicdata()
  {

      $this->publicdata=array(
          'partner'			=>	$this->config['partner'],
          '_input_charset'	=>	$this->config['_input_charset'],
          'sign_type'			=>	$this->config['sign_type'],
          'sign'				=>	'',
          'notify_url'		=>	$this->config['notify_url'],
          'return_url'        =>  $this->config['return_url'],
          'it_b_pay'          =>  '15m',
      );
  }


  /**
   * 通知效验
   * @param array $data
   * @param $sign 要验证的签名
   */
  private function notice_check($data=array(),$sign='')
  {
      $data=$this->filt_arg($data);
      $str= $this->bulid_param($data);
      if($str!='')
      {
          switch($this->config['sign_type'])
          {
              case "MD5":
                  $result=($sign==md5($str.$this->config['md5key']));
                  break;
              default:
                  $result=$this->rsaVerify($str,$this->config['alipay_public_key'],$sign);
                  break;
          }
          return $result;
      }
      return false;
  }


  /**生成签名
   * @param string $data
   * @param string $keyfile
   * @return string
   */
  private function sign($data)
  {

      $data=$this->filt_arg($data);
      $oldStr=$str= $this->bulid_param($data);

      if($str!='')
      {
          switch($this->config['sign_type'])
          {
              case "MD5":
                  $str= md5($str.$this->config['md5key']);
                  break;
              default:
                  $str= $this->rsaSign($str);
                  break;
          }
      }

      return $str;
  }

  /**RSA-私钥加密
   * @param $data
   * @param string $keyfile
   * @return string
   */
  private function rsaSign($data,$keyfile='')
  {
      if($keyfile=='') $keyfile=__DIR__.'/rsa/'.$this->config['private_key'];
      $priKey = file_get_contents($keyfile);
      $res = openssl_get_privatekey($priKey);
      openssl_sign($data, $sign, $res);
      openssl_free_key($res);
      //base64编码
      return base64_encode($sign);
  }


  /**
   * 准备参与签名的数组
   * @param array $data
   */
  private function filt_arg($data=array())
  {
      //参数过滤
      if(count($this->filtParam)>0)
      {
          foreach($this->filtParam as $key=>$val)
          {
              if(isset($data[$val])) unset($data[$val]);
          }
      }
      return $data;
  }



  /**组装参数
   * @param array $data 传入的字符
   * @return string 返回值
   */
  private function bulid_param($data=array(),$urlencode=false)
  {
      $str='';
      ksort($data);
      reset($data);
      foreach($data as $key=>$val)
      {
          if(gettype($val)!='array' && $val!='')
          {
              if($str!='') $str.="&";
              $str.="$key=".($urlencode?urlencode($val):$val);
          }
      }
      return $str;
  }


  /**
   * 获取返回时的签名验证结果
   * @param $para_temp 通知返回来的参数数组
   * @param $sign 返回的签名结果
   * @return 签名验证结果
   */
  private function getSignVeryfy($para_temp, $sign)
  {
      $para_temp=$this->filt_arg($para_temp);
      $para_temp = $this->bulid_param($para_temp);
      return $this->rsaVerify($para_temp, trim($this->config['alipay_public_key']), $sign);
  }


  /** RSA验签
   * @param  $data 待签名数据
   * @param $ali_public_key_path 支付宝的公钥文件路径
   * @param $sign 要校对的的签名结果
   * @return 验证结果
   */
  private function rsaVerify($data, $ali_public_key_path, $sign)
  {
      $ali_public_key_path  = __DIR__.'/rsa/'.$ali_public_key_path;
      $pubKey = file_get_contents($ali_public_key_path);
      $res = openssl_get_publickey($pubKey);
      $dstr='';
      openssl_public_encrypt($sign,$dstr, $res);
      $result =(bool)openssl_verify($data,base64_decode($sign), $res);
      openssl_free_key($res);
      return $result;
  }



  /**
   * 获取传的值
   * @param string $key
   * @param string $default
   */
  private function g($key="",$default="")
  {
      $val=array_key_exists($key,$_REQUEST)?$_REQUEST[$key]:$default;
      return $val;
  }


  public function reback(){

  }

  public function checkOrder(){

  }

  /**
   * 日志
   * @param unknown $data
   */
  public function _log($data=[],$m='pay'){
      return;
      if(gettype($data)=='array' && count($data)>0)
      {
          $str="\r\n-------------------------------------------------------------[$m]".date("Y-m-d H:i:s")."----------\r\n";
          foreach($data as $key=>$val)
          {
              $str.="$key:$val\r\n";
          }
          file_put_contents(__DIR__."/".date("Ymd")."_log.txt", $str,FILE_APPEND);
      }

  }
}
